﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

namespace Sublimation.Behaviours
{
    public class EnemyUnitGoalBehaviour : Behaviour
    {
        protected WorldProperties worldProperties;
        protected EnemyUnit owner;
        protected float weight;
        public float getWeight() { return this.weight; }

        public EnemyUnitGoalBehaviour(WorldProperties worldProperties, EnemyUnit owner, float weight)
        {
            this.worldProperties = worldProperties;
            this.owner = owner;
            this.weight = weight;
        }

        // lets just check this behaviour every X updates - it doesn't change that often and it's kinda heavy
        private Vector2 lastResult;
        private int tickCount = 0;
        private const int TICKS_BETWEEN_UPDATES = 8;

        private Vector2 perimeterPosition;
        public Vector2 RunBehaviour()
        {
            // assign a goal to the enemy unit - currently not worrying about sight range here (towers are big!)
            if (tickCount == 0)
            {
                tickCount = TICKS_BETWEEN_UPDATES;


                Vector2 result = Vector2.Zero;

                // originally i thought about having them factor in the direction of all towers with a stronger weight for the closest, but then i realised that would be strange. Since it's like gravity you could end up trapping them.
                float distanceToClosestTower = 0.0f;
                foreach (Player player in worldProperties.Players)
                {
                    foreach (Tower tower in player.Towers)
                    {
                        Vector2 vectorToTower = (tower.Position - owner.Position); //XXX: should we bother taking into account origin or nearest edge? like collision code
                        if (result == Vector2.Zero || vectorToTower.Length() < distanceToClosestTower)
                        {
                            distanceToClosestTower = vectorToTower.Length();
                            result = vectorToTower;
                        }
                    }
                }

                // should we try to move at max speed? - up to the distance anyway, in which case perhaps we shouldn't change this. but then that would throw it out in relation to other movements. Hmm.
                // lets clamp it for now
                if (distanceToClosestTower > owner.MaxSpeed) result *= owner.MaxSpeed / distanceToClosestTower;

                lastResult = result * weight;
            }

            tickCount--;
            
            return lastResult;
        }

        protected Vector2 getRandomPerimeterPosition()
        {
            Vector2 position;

            int perimeterPosition = worldProperties.Random.Next(0, worldProperties.Map.Perimeter);
            if (perimeterPosition <= worldProperties.Map.WorldBounds.Width)
            {   
                // place on the top
                position = new Vector2(worldProperties.Map.WorldBounds.X + perimeterPosition, worldProperties.Map.WorldBounds.Y + 1);
            }
            else if (perimeterPosition <= worldProperties.Map.WorldBounds.Width + worldProperties.Map.WorldBounds.Height)
            {
                // right side
                perimeterPosition -= worldProperties.Map.WorldBounds.Width;
                position = new Vector2(worldProperties.Map.WorldBounds.X + worldProperties.Map.WorldBounds.Width - 1, worldProperties.Map.WorldBounds.Y + perimeterPosition);
            }
            else if (perimeterPosition <= worldProperties.Map.WorldBounds.Width * 2 + worldProperties.Map.WorldBounds.Height)
            {
                // bottom side
                perimeterPosition -= worldProperties.Map.WorldBounds.Width + worldProperties.Map.WorldBounds.Height;
                position = new Vector2(worldProperties.Map.WorldBounds.X + perimeterPosition, worldProperties.Map.WorldBounds.Y + worldProperties.Map.WorldBounds.Height - 1);
            }
            else
            {
                // left side
                perimeterPosition -= worldProperties.Map.WorldBounds.Width * 2 + worldProperties.Map.WorldBounds.Height;
                position = new Vector2(worldProperties.Map.WorldBounds.X + 1, worldProperties.Map.WorldBounds.Y + perimeterPosition);
            }

            return position;
        }
    }
}
